/*
 *   Copyright 2012-present OSBI Ltd
 *
 *   Licensed under the Apache License, Version 2.0 (the "License");
 *   you may not use this file except in compliance with the License.
 *   You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 *   Unless required by applicable law or agreed to in writing, software
 *   distributed under the License is distributed on an "AS IS" BASIS,
 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *   See the License for the specific language governing permissions and
 *   limitations under the License.
 */

// Packages
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import $ from 'jquery';
import 'jquery-ui/ui/widgets/draggable.js';
import { defer } from 'lodash';
import classnames from 'classnames';
import isEqual from 'react-fast-compare';
import { Tree } from 'antd';
import TruncateString from 'react-truncate-string';

// Utils
import { Saiku, Settings } from '../../../../utils';

// Styles
import './TreeDimensions.css';

// Components
const { TreeNode } = Tree;

class TreeDimensions extends Component {
  state = {
    defaultExpandedKeys: []
  };

  componentDidMount() {
    this.handleDraggable();
  }

  shouldComponentUpdate(nextProps, nextState) {
    return (
      !isEqual(this.props.dimensions, nextProps.dimensions) ||
      !isEqual(this.state.defaultExpandedKeys, nextState.defaultExpandedKeys)
    );
  }

  componentDidUpdate(prevProps, prevState) {
    if (!isEqual(prevProps.dimensions, this.props.dimensions)) {
      this.handleDraggable();
    }
  }

  componentWillUnmount() {
    if (this.$rootNode) {
      this.$rootNode.draggable('destroy');
    }
  }

  handleDraggable = () => {
    defer(() => {
      this.$rootNode = $(this.rootNode)
        .find('.sku-level-item')
        .not('.ui-draggable-disabled');

      this.$rootNode.draggable({
        cancel: '.not-draggable',
        connectToSortable: $(
          '.sku-rows-axis.sku-connectable,' +
            '.sku-columns-axis.sku-connectable,' +
            '.sku-filter-axis.sku-connectable'
        ),
        containment: $('.sku-query-designer-dialog'),
        cursorAt: { top: 10, left: 85 },
        helper: 'clone',
        opacity: 0.6,
        placeholder: 'placeholder',
        scroll: false,
        tolerance: 'touch',
        start: (event, ui) => {
          const $levelElem = ui.helper.find('.sku-level-data');

          ui.helper.html($levelElem);
        },
        zIndex: 1000
      });
    });
  };

  onExpandTreeNode = (expandedKeys, { expanded, node }) => {
    if (
      node.props.className === 'sku-dimensions-group' ||
      node.props.className === 'sku-hierarchies-group'
    ) {
      this.setState({ defaultExpandedKeys: expandedKeys });
    }

    if (expanded) {
      this.handleDraggable();
    }
  };

  onSelectTreeNode = (
    selectedKeys,
    { selected, selectedNodes, node, event }
  ) => {
    if (
      node.props.className === 'sku-dimensions-group' ||
      node.props.className === 'sku-hierarchies-group'
    ) {
      node.onExpand(event);
      this.handleDraggable();
    }
  };

  renderTreeDimensions() {
    const { draggableId, dimensions } = this.props;

    return dimensions.map(
      dimension =>
        dimension.name !== 'Measures' &&
        (typeof dimension['visible'] === 'undefined' ||
          dimension['visible']) && (
          <TreeNode
            key={`sku-${dimension.caption}-dimension`}
            className="sku-dimensions-group"
            title={
              <span
                title={
                  dimension.description
                    ? dimension.description
                    : dimension.caption
                }
              >
                <TruncateString text={dimension.caption} />
              </span>
            }
          >
            {dimension.hierarchies.map(
              hierarchy =>
                (typeof hierarchy['visible'] === 'undefined' ||
                  hierarchy['visible']) &&
                ((Settings.DIMENSION_HIDE_HIERARCHY === 'NONE' &&
                  dimension.hierarchies.length > 1) ||
                (Settings.DIMENSION_HIDE_HIERARCHY === 'SINGLE_LEVEL' &&
                  ((Settings.DIMENSION_SHOW_ALL &&
                    hierarchy['levels'].length > 3) ||
                    (!Settings.DIMENSION_SHOW_ALL &&
                      hierarchy['levels'].length > 2))) ? (
                  <TreeNode
                    key={`sku-${hierarchy.caption}-hierarchy`}
                    className="sku-hierarchies-group"
                    title={
                      <span
                        title={
                          hierarchy.description
                            ? hierarchy.description
                            : hierarchy.caption
                        }
                        hierarchy={hierarchy.name}
                      >
                        <TruncateString text={hierarchy.caption} />
                      </span>
                    }
                  >
                    {hierarchy.levels.map(
                      (level, index) =>
                        (Settings.DIMENSION_SHOW_ALL ||
                          level.name !== '(All)') &&
                        (typeof level['visible'] === 'undefined' ||
                          level['visible']) && (
                          <TreeNode
                            key={Saiku.uid(level.caption)}
                            className={classnames('sku-level-item', {
                              'ui-draggable-disabled': level.isDragDisabled
                            })}
                            disabled={level.isDragDisabled}
                            selectable={false}
                            title={
                              <span
                                className="sku-level-data"
                                dragsourceid={draggableId}
                                dragsourceindex={index}
                                title={
                                  (Settings.DIMENSION_HIDE_HIERARCHY ===
                                    'SINGLE_LEVEL' ||
                                    Settings.DIMENSION_HIDE_HIERARCHY ===
                                      'ALL') &&
                                  dimension.hierarchies.length > 1
                                    ? `${hierarchy.caption} - ${
                                        level.description
                                          ? level.description
                                          : level.caption
                                      }`
                                    : level.description
                                    ? level.description
                                    : level.caption
                                }
                                dimension={dimension.name}
                                hierarchyuniquename={hierarchy.uniqueName}
                                hierarchy={hierarchy.name}
                                level={level.name}
                              >
                                <TruncateString text={level.caption} />
                              </span>
                            }
                          />
                        )
                    )}
                  </TreeNode>
                ) : (
                  hierarchy.levels.map(
                    (level, index) =>
                      (Settings.DIMENSION_SHOW_ALL || level.name !== '(All)') &&
                      (typeof level['visible'] === 'undefined' ||
                        level['visible']) && (
                        <TreeNode
                          key={Saiku.uid(level.caption)}
                          className={classnames('sku-level-item', {
                            'ui-draggable-disabled': level.isDragDisabled
                          })}
                          disabled={level.isDragDisabled}
                          selectable={false}
                          title={
                            <span
                              className="sku-level-data"
                              dragsourceid={draggableId}
                              dragsourceindex={index}
                              title={
                                (Settings.DIMENSION_HIDE_HIERARCHY ===
                                  'SINGLE_LEVEL' ||
                                  Settings.DIMENSION_HIDE_HIERARCHY ===
                                    'ALL') &&
                                dimension.hierarchies.length > 1
                                  ? `${hierarchy.caption} - ${
                                      level.description
                                        ? level.description
                                        : level.caption
                                    }`
                                  : level.description
                                  ? level.description
                                  : level.caption
                              }
                              dimension={dimension.name}
                              hierarchyuniquename={hierarchy.uniqueName}
                              hierarchy={hierarchy.name}
                              level={level.name}
                            >
                              <TruncateString text={level.caption} />
                            </span>
                          }
                        />
                      )
                  )
                ))
            )}
          </TreeNode>
        )
    );
  }

  render() {
    const { defaultExpandedKeys } = this.state;

    return (
      <div
        className="sku-dimensions-container"
        ref={node => (this.rootNode = node)}
      >
        <Tree
          className="sku-dimensions-tree"
          onExpand={this.onExpandTreeNode}
          onSelect={this.onSelectTreeNode}
          defaultExpandedKeys={defaultExpandedKeys}
        >
          {this.renderTreeDimensions()}
        </Tree>
      </div>
    );
  }
}

TreeDimensions.propTypes = {
  draggableId: PropTypes.string.isRequired,
  dimensions: PropTypes.array
};

export default TreeDimensions;
